﻿/*
 * CallStack.h
 */
#ifndef __GDK_CALLSTACK_H__
#define __GDK_CALLSTACK_H__

#include <gdk/core/Types.h>
#include <gdk/core/atomics.h>



#ifdef _WIN32



namespace gdk
{


#define CALLSTACKCHUNKSIZE 32 // Size, in frames (DWORDs), of each CallStack Chunk. 


//////////////////////////////////////////////////////////////////////////////// 
// 
//  The CallStack Class 
// 
//    This data structure is similar in concept to a STL vector, but is 
//    specifically tailored for use by VLD, making it more efficient than a 
//    standard STL vector. 
// 
//    A CallStack is made up of a number of "Chunks" which are arranged in a 
//    linked list. Each Chunk contains an array of frames (each frame is 
//    represented by a program counter address). If we run out of space when 
//    pushing new frames onto an existing chunk in the CallStack Chunk list, 
//    then a new Chunk is allocated and appended to the end of the list. In this 
//    way, the CallStack can grow dynamically as needed. New frames are always 
//    pushed onto the Chunk at the end of the list known as the "top" Chunk. 
// 
//    When a CallStack is no longer needed (i.e. the memory block associated 
//    with a CallStack has been freed) the memory allocated to the CallStack is 
//    not actually freed. Instead, the CallStack's data is simply reset so that 
//    the CallStack can be reused later without needing to reallocate memory. 
//
class GDK_CORE_EXPORT CallStack
{
private: 
	// The chunk list is made of a linked list of Chunks. 
	class Chunk
	{ 
	public:
		Chunk     *_next; 
		DWORD_PTR  _frames[CALLSTACKCHUNKSIZE]; 

	public: 
		Chunk () {} 
		Chunk (const Chunk &) { GDK_ASSERT(false); } // Do not make copies of Chunks! 
	};

public:
	class Callback{
	public:
		virtual void report(const char *text) =0;
	};

private:
	// Private Data 
	int32_t           _refs;
	size_t            _capacity; // Current capacity limit (in frames) 
	size_t            _size;     // Current size (in frames) 
	CallStack::Chunk  _store;    // Pointer to the underlying data store (i.e. head of the Chunk list) 
	CallStack::Chunk *_topChunk; // Pointer to the Chunk at the top of the stack 
	size_t            _topIndex; // Index, within the top Chunk, of the top of the stack

private:
	CallStack ();
	CallStack (const CallStack &source);
	~CallStack ();

	// Public APIs - see each function definition for details. 
	bool operator == (const CallStack &other);
	DWORD_PTR operator [] (size_t index);

	void clear ();
	void push (DWORD_PTR programcounter);
	size_t size ();
	void getStackTrace ();
	void getStackTrace_fast ();

public:
	void addRef(void) { atomic_increment(&_refs); }
	void dump (Callback &callback);
	void destroy (void);

public:
	static CallStack* getCallStack ();
	static CallStack* getCallStack_fast ();
}; 


//////////////////////////////////////////////////
class GDK_CORE_EXPORT DumpCallStack_VS : public CallStack::Callback
{
public:
	virtual void report(const char *text);
};

//////////////////////////////////////////////////
class GDK_CORE_EXPORT DumpCallStack_Console : public CallStack::Callback
{
public:
	virtual void report(const char *text);
};

//////////////////////////////////////////////////
class GDK_CORE_EXPORT DumpCallStack_Log : public CallStack::Callback
{
public:
	virtual void report(const char *text);
};




}//namespace gdk



#endif //_WIN32


#endif //__GDK_CALLSTACK_H__

